//
//  XS_DownloadManager.swift
//  XueDao
//
//  Created by Mac on 2020/12/15.
//

import UIKit
import AliyunMediaDownloader

//下载模型类
class XS_DownloadModel: XS_BaseModel {
    var curriculumModel = XS_KCcurriculumM()
    var hourModels : [XS_KCqueryHoursM] = []
    var hourModel = XS_KCqueryHoursM()
    var listModel = XS_KCcurriculumHourDtoListM()
}

protocol XS_DownloadManagerDelegate {
    func downloadManager(downloadManager : XS_DownloadManager, downloader : AliMediaDownloader, didError:AVPErrorModel)
    func downloadManager(downloadManager : XS_DownloadManager, downloader : AliMediaDownloader, didProgress:Int32)
    func downloadManager(downloadManager : XS_DownloadManager, downloader : AliMediaDownloader, didComplete:Bool)
}

//下载路径
public let XS_DownloadManager_CourseFilePath = NSHomeDirectory() + "/Documents/Courses"
//存储模型key
public let XS_DownloadManager_SaveKey = "XS_DownloadManager_SaveKey"

public let XS_DownloadManager_Queue_SaveKey = "XS_DownloadManager_Queue_SaveKey"


public let XS_DownloadManager_ProgressNoti = "XS_DownloadManager_ProgressNoti"

public let isOpenResumeDownload = false //是否开启断点续传功能

public class XS_DownloadManager: NSObject {
    
    static let shared = XS_DownloadManager()
    
    var currentModel : XS_DownloadModel?//当前正在下载模型
    
    var downloadQueue : [XS_DownloadModel] = []//下载队列
    var isDownloading = false//是否在下载
    
    var delegate : XS_DownloadManagerDelegate?
        
    lazy var downloader : AliMediaDownloader? = {
        var downloader = AliMediaDownloader.init()
        downloader?.setSaveDirectory(XS_DownloadManager_CourseFilePath)
        downloader?.delegate = self
        return downloader
    }()
    
    
    /// 创建文件夹
    public class func createDirectory(){
        let fileManager = FileManager.default
        do{
            try fileManager.createDirectory(atPath: XS_DownloadManager_CourseFilePath,
                                    withIntermediateDirectories: true, attributes: nil)
            xsDebug {
                print("创建文件夹成功")
            }
        }catch{
            xsDebug {
                print("创建文件夹失败")
            }
        }
    }
    
    
    /// 获取所有文件
    /// - Returns: 所有文件路径
    public func getAllFile(filePath : String) -> [String]{
        let fileManager = FileManager.default
        do{
            let contentsOfPath = try fileManager.contentsOfDirectory(atPath: filePath)
            return contentsOfPath
        }catch{
            return []
        }
    }
    
    
    /// 如果没有在下载，进入下载队列
    /// - Parameter downloadModel: 下载模型
    func download(downloadModel : XS_DownloadModel) {
//        for model in downloadQueue {
//            if model.listModel.id == downloadModel.listModel.id && model.listModel.curriculumHourName == downloadModel.listModel.curriculumHourName {
//                return
//            }
//        }
        downloadQueue.append(downloadModel)
        //存储下载队列
        if isOpenResumeDownload {
            var tempArray = [String]()
            for subModel in downloadQueue {
                tempArray.append(subModel.toJSONString() ?? "")
            }
            UserDefaults.standard.setValue(tempArray, forKey: XS_DownloadManager_Queue_SaveKey)
            UserDefaults.standard.synchronize()
        }
        if isDownloading {
            return
        }else{
            requestDownloadData(downloadModel: downloadModel)
        }
    }
    
    func resumeDownload(){
        var tempArray = [XS_DownloadModel]()
        let storageQueue = UserDefaults.standard.value(forKey: XS_DownloadManager_Queue_SaveKey)
        if storageQueue != nil {
            let storageQueueArray = storageQueue as! [String]
            if storageQueueArray.count > 0 {
                for json in storageQueueArray {
                    let downloadModel = XS_DownloadModel.deserialize(from: json)
                    tempArray.append(downloadModel!)
                }
            }
        }
        downloadQueue = tempArray
        if downloadQueue.count > 0 {
            let downloadModel = downloadQueue.first
            UIApplication.shared.keyWindow?.makeToast("当前下载:"+(downloadModel?.listModel.curriculumHourName ?? ""))
            requestDownloadData(downloadModel: downloadModel!)
        }
    }
    
    
    /// 获取下载所需要的数据
    /// - Parameter downloadModel: 下载的模型
    func requestDownloadData(downloadModel : XS_DownloadModel){
        isDownloading = true
        currentModel = downloadModel
        let source = AVPVidStsSource.init(vid: downloadModel.listModel.sts.vid, accessKeyId: downloadModel.listModel.sts.akId, accessKeySecret: downloadModel.listModel.sts.akScret, securityToken: downloadModel.listModel.sts.stk, region: downloadModel.listModel.sts.regionId)
        self.downloader?.prepare(withVid: source)
    }
}

extension XS_DownloadManager : AMDDelegate{
    /**
     @brief 下载准备完成事件回调
     @param downloader 下载downloader指针
     @param info 下载准备完成回调，@see AVPMediaInfo
     */
    public func onPrepared(_ downloader: AliMediaDownloader!, mediaInfo info: AVPMediaInfo!) {
        for trackInfo in info.tracks {
            if trackInfo.trackDefinition == "LD" {
                downloader.selectTrack(trackInfo.trackIndex)
                downloader.start()
                break
            }
        }
    }
    /**
     @brief 错误代理回调
     @param downloader 下载downloader指针
     @param errorModel 播放器错误描述，参考AliVcPlayerErrorModel
     */
    public func onError(_ downloader: AliMediaDownloader!, errorModel: AVPErrorModel!) {
        isDownloading = false
        if delegate != nil {
            delegate?.downloadManager(downloadManager: self, downloader: downloader, didError: errorModel)
        }
    }
    
    /**
     @brief 下载进度回调
     @param downloader 下载downloader指针
     @param percent 下载进度 0-100
     */
    public func onDownloadingProgress(_ downloader: AliMediaDownloader!, percentage percent: Int32) {
        if delegate != nil {
            delegate?.downloadManager(downloadManager: self, downloader: downloader, didProgress: percent)
        }
        NotificationCenter.default.post(name: NSNotification.Name.init(XS_DownloadManager_ProgressNoti), object: percent)
    }
    
    /**
     @brief 下载完成回调
     @param downloader 下载downloader指针
     */
    public func onCompletion(_ downloader: AliMediaDownloader!) {
        if delegate != nil {
            delegate?.downloadManager(downloadManager: self, downloader: downloader, didComplete: true)
        }
        //章/节_id
        let newFilePath = String.init(format: "%@/%@/%@_%@_%ld.mp4", XS_DownloadManager_CourseFilePath,currentModel?.curriculumModel.curriculumName ?? "",currentModel?.hourModel.chapterName as! CVarArg,currentModel?.listModel.curriculumHourName as! CVarArg,currentModel?.listModel.id as! CVarArg)
        let newDic = String.init(format: "%@/%@/", XS_DownloadManager_CourseFilePath,currentModel?.curriculumModel.curriculumName ?? "",currentModel?.hourModel.chapterName as! CVarArg)
        
        let fileManager = FileManager.default
        do{
            try fileManager.createDirectory(atPath: newDic,
                                    withIntermediateDirectories: true, attributes: nil)
            xsDebug {
                print("创建文件夹成功")
            }
        }catch{
            xsDebug {
                print("创建文件夹失败")
            }
        }
        
        let ret = renameFile(originPath: downloader.downloadedFilePath, toNewName: newFilePath)
        currentModel?.listModel.filePath = newFilePath
        currentModel?.listModel.progress = 100
        saveModel(model: currentModel)
        currentModel = nil
        self.isDownloading = false
        downloadQueue.removeFirst()
        if isOpenResumeDownload {
            //存储下载队列
            var tempArray = [String]()
            for subModel in downloadQueue {
                tempArray.append(subModel.toJSONString() ?? "")
            }
            UserDefaults.standard.setValue(tempArray, forKey: XS_DownloadManager_Queue_SaveKey)
            UserDefaults.standard.synchronize()
        }
        NotificationCenter.default.post(name: NSNotification.Name.init(.downloadingQueueUpdateNotification), object: nil)
        if downloadQueue.count > 0 {
            requestDownloadData(downloadModel: downloadQueue.first!)
        }
    }
    
    
    /// 重命名文件
    /// - Parameters:
    ///   - originPath: 原始路径
    ///   - toNewName: 新路径
    /// - Returns: 是否成功
    func renameFile(originPath : String, toNewName : String) -> Bool{
        let fileManager = FileManager.default
        let originURL = URL.init(fileURLWithPath: originPath)
        let newURL = URL.init(fileURLWithPath: toNewName)
        
        
        
        var state = false
        do{
            try fileManager.moveItem(at: originURL, to: newURL)
            state = true
        }catch let error as NSError{
            debugPrint(error)
            state = false
        }
        return state
    }
    
    
    /// 移除文件
    func removeFile(model:XS_KCcurriculumHourDtoListM){
        //移除文件路径
        let fileManager = FileManager.default
        do{
            let ret = try fileManager.fileExists(atPath: model.filePath)
            if ret {
                do {
                    try FileManager.default.removeItem(atPath: model.filePath)
                }catch let error as NSError{
                    debugPrint(error)
                }
            }
        }catch{
            
        }
        //移除模型
        var models = XS_DownloadManager.shared.getModels()
        var tempArray : [XS_KCcurriculumHourDtoListM] = []
        var tempHoursArray : [XS_KCqueryHoursM] = []
        for downloadModel in models {
            tempHoursArray = downloadModel.hourModels
            var progress = 0
            for index in 0...downloadModel.hourModels.count - 1 {
                var chapterModel = downloadModel.hourModels[index]
                for jndex in 0...chapterModel.curriculumHourDtoList.count - 1 {
                    let courseModel = chapterModel.curriculumHourDtoList[jndex]
                    if courseModel.id == model.id {
                        //更改进度
                        courseModel.progress = 0
                    }
                    progress = Int(courseModel.progress) + progress
                }
                //替换原有存储的downloadModel
                let array = UserDefaults.standard.value(forKey: XS_DownloadManager_SaveKey)
                if array != nil {
                    let arr = array as! [String]
                    var newArr = arr
                    var ret = false
                    var index = -1
                    var subModel = XS_DownloadModel()
                    for subStr in arr {
                        subModel = XS_DownloadModel.deserialize(from: subStr)!
                        if subModel.curriculumModel.id ==  downloadModel.curriculumModel.id{
                            index = arr.firstIndex(of: subStr) ?? -1
                            ret = true
                        }
                    }
                    if ret {
                        if progress == 0 {
                            newArr.remove(at: index)
                        }else{
                            newArr[index] = downloadModel.toJSONString() ?? ""
                        }
                    }
                    UserDefaults.standard.setValue(newArr, forKey: XS_DownloadManager_SaveKey)
                    UserDefaults.standard.synchronize()
                }
                break
            }
        }
        
    }
    
    /// 存储模型
    /// - Parameter model:下载模型
    func saveModel(model:XS_DownloadModel?){
        let array = UserDefaults.standard.value(forKey: XS_DownloadManager_SaveKey)
        if array != nil {
            let arr = array as! [String]
            var newArr = arr
            var ret = false
            var index = -1
            var downloadModel = XS_DownloadModel()
            for subStr in arr {
                downloadModel = XS_DownloadModel.deserialize(from: subStr)!
                if downloadModel.hourModel.id == model?.hourModel.id {
                    if let jndex = downloadModel.hourModel.curriculumHourDtoList.firstIndex(where: {$0.id == model?.listModel.id}) {
                        downloadModel.hourModel.curriculumHourDtoList[jndex] = model?.listModel ?? XS_KCcurriculumHourDtoListM()
                        if let kndex = downloadModel.hourModels.firstIndex(where: {$0.id == downloadModel.hourModel.id}) {
                            downloadModel.hourModels[kndex] = downloadModel.hourModel
                        }
                    }
                    //如果下载了同一章
                    ret = true
                    index = arr.firstIndex(of: subStr) ?? -1
                }else if downloadModel.curriculumModel.id == model?.curriculumModel.id{
                    //如果下载了同一个课程不同章
                    debugPrint("下载了同一个课程不同章")
                    if let jndex = downloadModel.hourModels.firstIndex(where: {$0.id == model?.hourModel.id}) {
                        downloadModel.hourModels[jndex] = model?.hourModel ?? XS_KCqueryHoursM()
                    }
                    ret = true
                    index = arr.firstIndex(of: subStr) ?? -1
                }
            }
            if ret {
                newArr[index] = downloadModel.toJSONString() ?? ""
            }else{
                newArr.append(model?.toJSONString() ?? "")
            }
            UserDefaults.standard.setValue(newArr, forKey: XS_DownloadManager_SaveKey)
        }else{
            UserDefaults.standard.setValue([model?.toJSONString()], forKey: XS_DownloadManager_SaveKey)
        }
        UserDefaults.standard.synchronize()
    }
    
    func removeAllFile(){
        let fileManager = FileManager.default
        do{
            let ret = try fileManager.fileExists(atPath: XS_DownloadManager_CourseFilePath)
            if ret {
                do {
                    try FileManager.default.removeItem(atPath: XS_DownloadManager_CourseFilePath)
                    UserDefaults.standard.setValue([], forKey: XS_DownloadManager_SaveKey)
                    UserDefaults.standard.synchronize()
                }catch let error as NSError{
                    debugPrint(error)
                }
            }
        }catch{
            
        }
    }
    
    
    /// 获取所有存储的模型
    /// - Returns: 模型数组
    func getModels() -> [XS_DownloadModel]{
        let array = UserDefaults.standard.value(forKey: XS_DownloadManager_SaveKey)
        if array != nil {
            let newArray = array as! [String]
            var arr : [XS_DownloadModel] = []
            for json in newArray {
                let model = XS_DownloadModel.deserialize(from: json)
                arr.append(model ?? XS_DownloadModel())
            }
            return arr
        }
        return []
    }
    
    func getSystemFreeSize() -> UInt64{
        let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
        var freeSize : UInt64 = 0
        do {
            let attr = try FileManager.default.attributesOfFileSystem(forPath: documentDirectoryPath ?? "")
            let size = attr[FileAttributeKey.systemFreeSize] as! UInt64
            freeSize = size
            return freeSize
        }catch let error as NSError{
            return 0
        }
    }
}

public extension String{
    static let downloadingQueueUpdateNotification = "downloadingQueueUpdateNotification"
    // 对象方法
        func getFileSize() -> UInt64  {
            var size: UInt64 = 0
            let fileManager = FileManager.default
            var isDir: ObjCBool = false
            let isExists = fileManager.fileExists(atPath: self, isDirectory: &isDir)
            // 判断文件存在
            if isExists {
                // 是否为文件夹
                if isDir.boolValue {
                    // 迭代器 存放文件夹下的所有文件名
                    let enumerator = fileManager.enumerator(atPath: self)
                    for subPath in enumerator! {
                        // 获得全路径
                        let fullPath = self.appending("/\(subPath)")
                        do {
                            let attr = try fileManager.attributesOfItem(atPath: fullPath)
                            size += attr[FileAttributeKey.size] as! UInt64
                        } catch  {
                            print("error :\(error)")
                        }
                    }
                } else {    // 单文件
                    do {
                        let attr = try fileManager.attributesOfItem(atPath: self)
                        size += attr[FileAttributeKey.size] as! UInt64
                        
                    } catch  {
                        print("error :\(error)")
                    }
                }
            }
            return size
        }
}
